package com.guanyu.u2cache.redis;

import com.guanyu.u2cache.annotation.useble.RedisSignal;
import com.guanyu.u2cache.cache.EventPush;
import com.guanyu.u2cache.cache.Level1ToLevel2Cache;
import com.guanyu.u2cache.cache.Level2Cache;
import com.guanyu.u2cache.elect.ElectMaster;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;

/**
 * 二级缓存配置信息
 *
 * @author zhouyunjian
 * @date 2023/10/30 16:58
 **/
@Slf4j
//@ConditionalOnBean(RedisSignal.class)
public class RedisCacheConfig {
    /**
     * 单机
     **/
    private static final int MODE_SINGLE = 1;
    /**
     * 哨兵
     **/
    private static final int MODE_SENTINEL = 2;
    /**
     * 集群
     **/
    private static final int MODE_CLUSTER = 3;
    /**
     * redis地址名
     **/
    private static final String REDIS_ADDRESS_MARK = "redis://";
    /**
     * 数据区
     **/
    @Value("${redisson.database:1}")
    private int database;
    /**
     * 登录密码
     **/
    @Value("${redisson.password:123456}")
    private String password;
    /**
     * 登录密码
     **/
    @Value("${redisson.isNoPass:true}")
    private Boolean isNoPass;
    /**
     * 超时时间
     **/
    @Value("${redisson.timeout:5000}")
    private int timeout;
    /**
     * 看门狗超时
     **/
    @Value("${redisson.watchDogTime:30000}")
    private int watchDogTimeout = 300000;
    /**
     * 最小活跃数
     **/
    @Value("${redisson.minIdle:10}")
    private int minIdle = 10;
    /**
     * 最大活跃数
     **/
    @Value("${redisson.maxIdle:10}")
    private int maxIdle = 10;
    /**
     * 线程数
     **/
    @Value("${redisson.threads:10}")
    private int threads = 10;
    /**
     * netty线程数
     **/
    @Value("${redisson.nettyThreads:5}")
    private int nettyThreads = 5;
    /**
     * 主从、集群地址
     **/
    @Value("${redisson.addresses:127.0.0.1:6379}")
    private String[] addresses;
    /**
     * 主机名称
     **/
    @Value("${redisson.masterName:foc}")
    private String masterName = "com/umax/foc";
    /**
     * redis模式:1-单机 2-集群 3-哨兵
     **/
    @Value("${redisson.mode:1}")
    private int mode = 1;
    /**
     * 是否启用redisson
     **/
    @Value("${redisson.use:true}")
    private boolean use = false;

    @Bean
    public Level2Cache level2Cache() {
        return new Level2CacheImpl();
    }

    @Bean
    public Level1ToLevel2Cache level1ToLevel2Cache() {
        return new Level1ToLevel2Cache();
    }

    @Bean
    public ElectMaster electMaster() {
        return new ElectMasterImpl();
    }

    @Bean
    public EventPush eventPush() {
        return new RedisEventPush();
    }



    @Bean("redissonClient")
    RedissonClient redissonClient() {
        RedissonClient redissonClient;
        if (!use) {
            log.info("[redisson]不使用redisson");
            return null;
        }
        switch (mode) {
            case MODE_SENTINEL:
                redissonClient = redisSentinel();
                break;
            case MODE_CLUSTER:
                redissonClient = redisCluster();
                break;
            default:
                redissonClient = redisSingle();
                break;
        }
        return redissonClient;
    }

    @DependsOn("redissonClient")
    @Bean
    public RedisMsgListener redisMsgListener() {
        return new RedisMsgListener();
    }


    /**
     * 单机模式
     */
    RedissonClient redisSingle() {
        log.info("[redissonConfig]单机模式加载，地址[{}]password[{}]", addresses, password);
        // 初始化配置:线程数配置
        Config config = initConfig();
        // 设置单机模式
        config.useSingleServer()
                // 设置数据位置
                .setDatabase(database)
                // 服务地址
                .setAddress(buildMultiAddresses(addresses)[0])
                // 密码
                .setPassword(isNoPass ? null : password)
                // 最小活跃数
                .setConnectionMinimumIdleSize(minIdle)
                // 最大活跃数
                .setConnectionPoolSize(maxIdle)
                //设置重试时间与频率
                .setRetryAttempts(3)
                .setRetryInterval(1000)
                //设置心跳间隔
                .setPingConnectionInterval(500)
                // 超时时间
                .setTimeout(timeout);
        RedissonClient redissonClient = Redisson.create(config);
        log.info("注册单机模式结束");
        return redissonClient;
    }


    /**
     * 哨兵模式
     */
    RedissonClient redisSentinel() {
        log.info("[redissonConfig]哨兵模式加载，地址[{}]password[{}]", addresses, password);
        // 初始化配置:线程数配置
        Config config = initConfig();
        // 设置单机模式
        config.useSentinelServers()
                // 设置数据位置
                .setDatabase(database)
                // 服务地址
                .addSentinelAddress(buildMultiAddresses(addresses))
                // 密码
                .setPassword(isNoPass ? null : password)
                // master名称
                .setMasterName(masterName)
                // master最小活跃数
                .setMasterConnectionMinimumIdleSize(minIdle)
                // master最大活跃数
                .setMasterConnectionPoolSize(maxIdle)
                // slave最小活跃数
                .setSlaveConnectionMinimumIdleSize(minIdle)
                // slave最大活跃数
                .setSlaveConnectionPoolSize(maxIdle)
                //设置重试时间与频率
                .setRetryAttempts(3)
                .setRetryInterval(1000)
                //设置心跳间隔
                .setPingConnectionInterval(500)
                // 返回超时
                .setTimeout(timeout)
                // 连接超时
                .setConnectTimeout(timeout);
        return Redisson.create(config);
    }

    /**
     * 集群模式
     */
    RedissonClient redisCluster() {
        log.info("[redissonConfig]集群模式加载，地址[{}]password[{}]", addresses, password);
        // 初始化配置:线程数配置
        Config config = initConfig();
        // 设置单机模式
        config.useClusterServers()
                // 服务地址
                .addNodeAddress(buildMultiAddresses(addresses))
                // 密码
                .setPassword(isNoPass ? null : password)
                // master最小活跃数
                .setMasterConnectionMinimumIdleSize(minIdle)
                // master最大活跃数
                .setMasterConnectionPoolSize(maxIdle)
                // slave最小活跃数
                .setSlaveConnectionMinimumIdleSize(minIdle)
                // slave最大活跃数
                .setSlaveConnectionPoolSize(maxIdle)
                //设置重试时间与频率
                .setRetryAttempts(3)
                .setRetryInterval(1000)
                //设置心跳间隔
                .setPingConnectionInterval(500)
                // 返回超时
                .setTimeout(timeout)
                //设置槽位覆盖检查
                .setCheckSlotsCoverage(false)
                // 连接超时
                .setConnectTimeout(timeout);
        RedissonClient redissonClient = Redisson.create(config);
        log.info("集群启动完成，生产redissonClient客户端");
        return redissonClient;
    }

    /**
     * config参数设置
     **/
    private Config initConfig() {
        Config config = new Config();
        //线程池数量：线程池数量被所有RTopic对象监听器，RRemoteService调用者和RExecutorService任务共同共享
        config.setThreads(threads)
                //这个线程池数量是在一个Redisson实例内，被其创建的所有分布式数据类型和服务，以及底层客户端所一同共享的线程池里保存的线程数量
                .setNettyThreads(nettyThreads)
                //看门狗超时时间:30 000ms
                .setLockWatchdogTimeout(watchDogTimeout);
        return config;
    }

    /**
     * 哨兵/集群服务地址
     **/
    private String[] buildMultiAddresses(String[] addresses) {
        // 新服务地址
        String[] newAdds = new String[addresses.length];
        for (int i = 0; i < addresses.length; i++) {
            newAdds[i] = REDIS_ADDRESS_MARK + addresses[i];
        }
        return newAdds;
    }
}
